package org.hughie.springframework.context.annotation;

import cn.hutool.core.util.StrUtil;
import org.hughie.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.hughie.springframework.beans.factory.config.BeanDefinition;
import org.hughie.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.hughie.springframework.stereotype.Component;

import java.util.Set;

/**
 * @author hughie.cheng
 * @since 2023/9/13
 */
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
    private BeanDefinitionRegistry registry;

    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
        this.registry = registry;
    }

    public void doScan(String... basePackages) {
        for (String basePackage : basePackages) {
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            for (BeanDefinition candidate : candidates) {
                String beanScope = resolveBeanScope(candidate);
                if (StrUtil.isNotEmpty(beanScope)) {
                    candidate.setScope(beanScope);
                }
                //将扫描到的bean在BeanDefinitionRegistry中注册
                registry.registerBeanDefinition(determineBeanName(candidate), candidate);
            }
        }
        // 注册处理注解的 BeanPostProcessor（@Autowired、@Value）
        registry.registerBeanDefinition("internalAutowiredAnnotationProcessor", new BeanDefinition(AutowiredAnnotationBeanPostProcessor.class));
    }

    /**
     * 获得@Scope配置的值
     */
    String resolveBeanScope(BeanDefinition beanDefinition) {
        Class<?> beanClass = beanDefinition.getBeanClass();
        Scope scope = beanClass.getAnnotation(Scope.class);
        if (scope != null) return scope.value();
        return StrUtil.EMPTY;
    }

    /**
     * 获得bean的name
     * 如果@Component注解中有配置则优先使用自定义配置，否则使用类名的首字母小写
     *
     * @return bean的名称
     */
    String determineBeanName(BeanDefinition beanDefinition) {
        Class<?> beanClass = beanDefinition.getBeanClass();
        Component component = beanClass.getAnnotation(Component.class);
        if (StrUtil.isNotEmpty(component.value())) {
            return component.value();
        }
        return StrUtil.lowerFirst(beanClass.getSimpleName());
    }
}
